﻿using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.SceneManagement;
using XLua;
using ZLMsg;

namespace ZL_Framework.Game
{
    /// <summary>
    /// 底板管理
    /// </summary>
    public class BoardManager : MonoBehaviour, IMsgReceiver
    {
        public static bool IS_STARTGAME;
        public List<ShapePool> shapeItemPool = new List<ShapePool>();  //图形池
        public GameObject tile;//底板预设
        public int xSize, ySize;    //底板个数
        public Vector2 boardSize;   //底板尺寸
        public float shapeFallSpeed = 0.3f; //图形下落速度
        public int dyeShowCondition = 5; //染色图形出现条件

        public ShapeItem[,] shapeItems; //当前所有的图形列表
        public GameObject[,] tileItems; //当前所有的图形列表

        public AnimationCurve fallCurve;

        public bool isInclined; //是否可以斜着消

        private Transform boardParentTF, shapeParentTF;
        private MouseInputer mMouseInputer;


        private void Awake()
        {
            this.RegisterLogicMsg(MsgName.MSG_GAME_START, StartGame);
            this.RegisterLogicMsg(MsgName.MSG_GAME_HINT, HintRemoveShape);
        }

        public void StartGame(IMsgParam obj)
        {
            IS_STARTGAME = true;
            Debug.Log("游戏开始");
            mMouseInputer = MouseInputer.Instance;
            StartCoroutine(CreateBoard(boardSize.x, boardSize.y));
        }

        //void Start()
        //{
        //    mMouseInputer = MouseInputer.Instance;
        //    StartCoroutine(CreateBoard(boardSize.x, boardSize.y));
        //}

        /// <summary>
        /// 创建底板
        /// </summary>
        /// <param name="xOffset"></param>
        /// <param name="yOffset"></param>
        private IEnumerator CreateBoard(float xOffset, float yOffset)
        {
            GameObject boardParent = new GameObject("boardParent");
            boardParentTF = boardParent.transform;
            boardParentTF.parent = transform;
            GameObject shapeParent = new GameObject("shapeParent");
            shapeParentTF = shapeParent.transform;
            shapeParentTF.parent = transform;
            shapeItems = new ShapeItem[xSize, ySize];
            tileItems = new GameObject[xSize, ySize];
            float startX = transform.position.x;
            float startY = transform.position.y;

            for (int y = 0; y < ySize; y++)
            {
                for (int x = 0; x < xSize; x++)
                {
                    Vector3 curPos = new Vector3(startX + (xOffset * x), startY + (yOffset * y), 0);
                    GameObject newTile = Instantiate(tile, curPos, Quaternion.identity);
                    newTile.transform.parent = boardParent.transform;
                    tileItems[x, y] = newTile;

                    ShapeItem shape = CreateShapeItem(ShapeItenType.Normal, curPos, true);
                    shape.SetShapeItemPos(x, y);
                    shape.name = shape.name + x.ToString() + y.ToString();
                    shapeItems[x, y] = shape;
                }
                yield return new WaitForSeconds(0.07f);
            }
            CheckCanRemoveShapeMethod();
        }

        /// <summary>
        /// 创建图案
        /// </summary>
        /// <param name="_itenType">类型</param>
        /// <param name="_pos">位置</param>
        /// <param name="_isLeapMove">是否需要缓动动画</param>
        /// <returns></returns>
        private ShapeItem CreateShapeItem(ShapeItenType _itenType, Vector3 _pos, bool _isLeapMove)
        {
            int max = shapeItemPool.Count;
            for (int i = 0; i < max; i++)
            {
                ShapePool curShapePool = shapeItemPool[i];
                if (curShapePool.shapeItem.shapeItenType == _itenType)
                {
                    ShapeItem shape = Instantiate(curShapePool.shapeItem, _pos, Quaternion.identity);
                    shape.InitShape(this, shapeParentTF, _isLeapMove, shapeFallSpeed, fallCurve, boardSize);
                    return shape;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取可以被选中的图形
        /// </summary>
        /// <param name="_item"></param>
        /// <returns></returns>
        public List<ShapeItem> GetCanLineShapeItem(ShapeItem _item, bool isShowCanLine = false)
        {
            SetShapeActiveFalse();
            List<ShapeItem> shapes = new List<ShapeItem>();
            Vector2 pos_left = new Vector2(_item.shapePos.x - 1, _item.shapePos.y);
            Vector2 pos_right = new Vector2(_item.shapePos.x + 1, _item.shapePos.y);
            Vector2 pos_up = new Vector2(_item.shapePos.x, _item.shapePos.y + 1);
            Vector2 pos_down = new Vector2(_item.shapePos.x, _item.shapePos.y - 1);

            ShapeItem item_left = GetShapeItem(pos_left);
            if (item_left != null)
            {
                shapes.Add(item_left);
                item_left.isActive = true;
            }
            ShapeItem item_right = GetShapeItem(pos_right);
            if (item_right != null)
            {
                shapes.Add(item_right);
                item_right.isActive = true;
            }
            ShapeItem item_up = GetShapeItem(pos_up);
            if (item_up != null)
            {
                shapes.Add(item_up);
                item_up.isActive = true;
            }
            ShapeItem item_down = GetShapeItem(pos_down);
            if (item_down != null)
            {
                shapes.Add(item_down);
                item_down.isActive = true;
            }

            if (isInclined)
            {
                Vector2 pos_up_left = new Vector2(_item.shapePos.x - 1, _item.shapePos.y + 1);
                Vector2 pos_up_right = new Vector2(_item.shapePos.x + 1, _item.shapePos.y + 1);
                Vector2 pos_down_left = new Vector2(_item.shapePos.x - 1, _item.shapePos.y - 1);
                Vector2 pos_down_right = new Vector2(_item.shapePos.x + 1, _item.shapePos.y - 1);

                ShapeItem item_up_left = GetShapeItem(pos_up_left);
                if (item_up_left != null)
                {
                    shapes.Add(item_up_left);
                    item_up_left.isActive = true;
                }
                ShapeItem item_up_right = GetShapeItem(pos_up_right);
                if (item_up_right != null)
                {
                    shapes.Add(item_up_right);
                    item_up_right.isActive = true;
                }
                ShapeItem item_down_left = GetShapeItem(pos_down_left);
                if (item_down_left != null)
                {
                    shapes.Add(item_down_left);
                    item_down_left.isActive = true;
                }
                ShapeItem item_down_right = GetShapeItem(pos_down_right);
                if (item_down_right != null)
                {
                    shapes.Add(item_down_right);
                    item_down_right.isActive = true;
                }
            }

#if UNITY_EDITOR
            if (isShowCanLine)
            {
                for (int i = 0; i < shapes.Count; i++)
                {
                    //shapes[i].SetColor(Color.green);
                }
            }
#endif
            return shapes;
        }

        /// <summary>
        /// 本次操作结束
        /// </summary>
        /// <param name="_shapes"></param>
        public IEnumerator LineEnd(List<ShapeItem> _shapes)
        {
            if (_shapes != null)
            {
                curItemAnimPlayedNum = 0;
                ShapeItem dyeItemRoot = null;
                if (_shapes.Count >= dyeShowCondition)
                {
                    dyeItemRoot = _shapes[_shapes.Count - 1];
                }
                int max = _shapes.Count;
                for (int i = 0; i < max; i++)
                {
                    ShapeItem shape = _shapes[i];
                    SetShapeItem(shape.shapePos, null);
                    shape.DestroyShape(ItemCount);
                }
                if (_shapes.Count >= dyeShowCondition && dyeItemRoot != null)
                {
                    CreateDyeShape(dyeItemRoot.shapePos, dyeItemRoot.shapeIndex);
                }

                while (curItemAnimPlayedNum < _shapes.Count)
                {
                    yield return null;
                }
                yield return new WaitForSeconds(shapeFallSpeed);
                SupplementShape();
                CheckCanRemoveShapeMethod();
            }
        }

        private void CreateDyeShape(Vector2 _pos, int dyeindex)
        {
            Vector3 tfPos = tileItems[(int)_pos.x, (int)_pos.y].transform.position;
            ShapeItemDye item = CreateShapeItem(ShapeItenType.Dye, tfPos, false) as ShapeItemDye;
            item.SetShapeItemPos(_pos);
            item.dyeIndex = dyeindex;
            SetShapeItem(_pos, item);
        }

        private int curItemAnimPlayedNum;
        private void ItemCount()
        {
            curItemAnimPlayedNum++;
        }

        /// <summary>
        /// 设置图形
        /// </summary>
        /// <param name="_pos"></param>
        /// <param name="_shape"></param>
        private void SetShapeItem(Vector2 _pos, ShapeItem _shape)
        {
            int pos_x = (int)_pos.x;
            int pos_y = (int)_pos.y;
            if (pos_x >= 0 && pos_y >= 0 && pos_x < xSize && pos_y < ySize)
            {
                shapeItems[pos_x, pos_y] = _shape;
            }
        }

        /// <summary>
        /// 获取图形
        /// </summary>
        /// <param name="_pos">坐标</param>
        /// <returns></returns>
        public ShapeItem GetShapeItem(Vector2 _pos)
        {
            int pos_x = (int)_pos.x;
            int pos_y = (int)_pos.y;
            if (pos_x >= 0 && pos_y >= 0 && pos_x < xSize && pos_y < ySize)
            {
                return shapeItems[pos_x, pos_y];
            }
            return null;
        }

        /// <summary>
        /// 全部图形初始化
        /// </summary>
        public void SetShapeActiveFalse()
        {
            for (int x = 0; x < xSize; x++)
            {
                for (int y = 0; y < ySize; y++)
                {
                    ShapeItem item = shapeItems[x, y];
                    if (item != null)
                    {
                        item.isActive = false;
                        item.SetColor(Color.white);
                    }
                }
            }
        }

        /// <summary>
        /// 补充图形
        /// </summary>
        public void SupplementShape()
        {
            for (int x = 0; x < xSize; x++)
            {
                for (int y = 0; y < ySize; y++)
                {
                    ShapeItem item = shapeItems[x, y];
                    if (item == null)
                    {
                        Vector3 tfPos = tileItems[x, y].transform.position;
                        Vector2 pos = new Vector2(x, y);
                        CheckUpShape(pos, tfPos, 1);
                        if (itemShape != null)
                        {
                            itemShape.SetShapeItemPos(pos);
                            //itemShape.transform.position = tfPos;
                            ShapeItem _item = itemShape;
                            _item.transform.DOMove(tfPos, shapeFallSpeed).SetEase(fallCurve);
                            SetShapeItem(pos, _item);
                            itemShape = null;
                        }
                    }
                }
            }
        }

        private ShapeItem itemShape;
        private void CheckUpShape(Vector2 _pos, Vector3 _tfPos, int _index)
        {
            int curY = (int)_pos.y + 1;
            if (curY < ySize)
            {
                Vector2 curPos = new Vector2(_pos.x, curY);
                ShapeItem item = GetShapeItem(curPos);
                if (item == null)
                {
                    CheckUpShape(curPos, _tfPos, _index++);
                }
                else
                {
                    itemShape = item;
                    SetShapeItem(curPos, null);
                }
            }
            else
            {
                Vector3 curPos = new Vector3(_tfPos.x, _tfPos.y + (boardSize.y * (_index + 1)), 0);
                itemShape = CreateShapeItem(ShapeItenType.Normal, curPos, false);
            }
        }

        /// <summary>
        /// 检查是否还有可消除的图形
        /// </summary>
        public void CheckCanRemoveShapeMethod()
        {
            StartCoroutine(CheckCanRemoveShape());
        }

        /// <summary>
        /// 检查是否还有可消除的图形
        /// </summary>
        private IEnumerator CheckCanRemoveShape()
        {
            mMouseInputer.CloseInput();
            isCanRemove = false;
            yield return new WaitForSeconds(shapeFallSpeed);
            for (int x = 0; x < xSize; x++)
            {
                if (isCanRemove)
                {
                    break;
                }
                for (int y = 0; y < ySize; y++)
                {
                    if (isCanRemove)
                    {
                        break;
                    }
                    ShapeItem item = shapeItems[x, y];
                    if (item != null && item.shapeItenType == ShapeItenType.Normal)
                    {
                        curCanShape?.Clear();
                        if (curCanShape == null)
                        {
                            curCanShape = new List<ShapeItem>();
                        }
                        CheckCanLineItem(item, 1);
                    }
                }
            }
            if (!isCanRemove)
            {
                Debug.Log("打乱");
                yield return new WaitForSeconds(1.5f);
                ReputBoard();
            }
            else
            {
                mMouseInputer.OpenInput();
                //HintRemoveShape();
            }

        }

        /// <summary>
        /// 提示当前可消除的一组图形
        /// </summary>
        public void HintRemoveShape(IMsgParam obj)
        {
            if (isCanRemove)
            {
                //curCanShape列表保存当前可消除的一组图形,可用作提示
                for (int i = 0; i < curCanShape.Count; i++)
                {
                    //curCanShape[i].SetColor(Color.red);
                    curCanShape[i].HintShape();
                }
            }
        }

        private ShapeItem preItem;
        private List<ShapeItem> curCanShape;
        private bool isCanRemove;
        private void CheckCanLineItem(ShapeItem _shape, int _checkNum)
        {
            curCanShape.Add(_shape);
            if (_checkNum <= 2)
            {
                preItem = _shape;
                List<ShapeItem> canLineList = GetCanLineShapeItem(_shape);
                for (int i = 0; i < canLineList.Count; i++)
                {
                    ShapeItem _item = canLineList[i];
                    if (_item.shapeIndex == _shape.shapeIndex && _item != preItem && !curCanShape.Contains(_item))
                    {
                        _checkNum++;
                        CheckCanLineItem(_item, _checkNum);
                    }
                }
            }
            else
            {
                isCanRemove = true;
                if (curCanShape.Count > 3)
                {
                    curCanShape.RemoveRange(3, curCanShape.Count - 3);
                }
            }
        }

        /// <summary>
        /// 刷新图形摆放位置
        /// </summary>
        private void ReputBoard()
        {
            Debug.Log("刷新");
            //先随机取出一半图形
            List<ShapeItem> newBoard = new List<ShapeItem>();
            while (newBoard.Count < xSize * ySize / 2)
            {
                int rx = Random.Range(0, xSize);
                int ry = Random.Range(0, ySize);

                ShapeItem item = GetShapeItem(new Vector2(rx, ry));
                if (!newBoard.Contains(item))
                {
                    newBoard.Add(item);
                }
            }

            //再取到另一半图形
            List<ShapeItem> newBoardBak = new List<ShapeItem>();
            for (int x = 0; x < xSize; x++)
            {
                for (int y = 0; y < ySize; y++)
                {
                    ShapeItem item = shapeItems[x, y];
                    if (item != null)
                    {
                        if (!newBoard.Contains(item))
                        {
                            newBoardBak.Add(item);
                        }
                    }
                }
            }

            //交换位置信息
            for (int i = 0; i < newBoard.Count; i++)
            {
                for (int j = 0; j < newBoardBak.Count; j++)
                {
                    ShapeItem newShape = newBoard[i];
                    ShapeItem newShapeBak = newBoardBak[j];
                    Vector2 itemShapePos = newShape.shapePos;
                    newShape.SetShapeItemPos(newShapeBak.shapePos);
                    newShapeBak.SetShapeItemPos(itemShapePos);
                    SetShapeItem(newShape.shapePos, newShape);
                    SetShapeItem(newShapeBak.shapePos, newShapeBak);

                    newShape.transform.DOMove(tileItems[(int)newShape.shapePos.x, (int)newShape.shapePos.y].transform.position, 0.5f);
                    newShapeBak.transform.DOMove(tileItems[(int)newShapeBak.shapePos.x, (int)newShapeBak.shapePos.y].transform.position, 0.5f);
                }
            }

            CheckCanRemoveShapeMethod();
            mMouseInputer.OpenInput();
        }
    }

    [System.Serializable]
    public class ShapePool
    {
        public string shapeType;
        public ShapeItem shapeItem;
    }
}